module factories.tile;

import factories.generated;
import factories.map;
import std.algorithm : min;

public import factories.generated : Resource, Terrain;

/// 气候
struct Climate {
	private ubyte g;

	this(uint temperature, uint humidity)
	in (temperature >= 0 && temperature <= 15 && humidity >= 0 && humidity <= 15) {
		g = cast(ubyte)((temperature & 0x0f) | (humidity << 4));
	}

@property:
	/// 温度
	uint temperature() const
	out (value; value >= 0 && value <= 15)
		=> g & 0x0f;

	void temperature(uint value)
	in (value >= 0 && value <= 15) {
		g = cast(ubyte)((g & 0xf0) | value);
	}

	/// 湿度
	uint humidity() const
	out (value; value >= 0 && value <= 15)
		=> g >> 4;

	void humidity(uint value)
	in (value >= 0 && value <= 15) {
		g = cast(ubyte)((g & 0x0f) | (value << 4));
	}
}

/// 渲染图块
struct Tile {
	alias climate this;

	/**
	* R:
	*	0-3位：地形id
	*	4-7位：高亮效果，植被密度，污染等
	* G:
	*	0-3位：温度
	*	4-7位：湿度
	* B:
	*	0-8位：建筑id
	* A:
	*	0-3位：建筑物等级，为0表示拆除
	*	4-6位：施工/生产进度
	*	7位：脏标记
	*/
	ubyte r;
	/// 气候
	Climate climate;
	/// 建筑
	Buildings building;
	ubyte a;

@property:
	/// 地形id
	Terrain terrain() const => cast(Terrain)(r & 0x0f);

	void terrain(Terrain value)
	in (value >= Terrain.min && value <= Terrain.max) {
		r = cast(ubyte)((r & 0xf0) | value);
	}

	/// 高亮效果
	uint highlight() const => r >> 4;

	void highlight(uint value) {
		r = cast(ubyte)((r & 0x0f) | (value << 4));
	}

	/// 建筑等级
	uint level() const => a & 0x0f;

	void level(uint value) {
		a = cast(ubyte)((a & 0x0f) | value);
	}

	/// 施工/生产进度
	uint progress() const => (a >> 4) & 0x07;

	void progress(uint value) {
		a = cast(ubyte)((a & 0x8f) | (value << 4));
	}

	/// 脏标记
	bool dirty() const => (a & 0x80) != 0;

	void dirty(bool value) {
		if (value != dirty)
			a = a ^ 0x80;
	}
}

/// 更新可视区地图
extern (C) export bool updateTiles(uint slot, uint width, uint height) {
	if (slot >= map.length)
		return false;

	//const x = slot % mapWidth;
	//const y = slot / mapWidth;
	//const xEnd = min(x + width, mapWidth);
	//const yEnd = min(y + height, mapWidth);
	//for (uint i = y; i < yEnd; i++) {
	//	for (uint j = x; j < xEnd; j++) {
	//		map[i * mapWidth + j].dirty = true;
	//	}
	//}
	return true;
}

unittest {
	import std.stdio;

	initMap();
	assert(updateTiles(0, mapWidth, mapWidth));

	for (uint y; y < mapWidth; y++) {
		for (uint x; x < mapWidth; x++) {
			const t = map[y * mapWidth + x].temperature;
			write(t, ' ');
		}
		writeln();
	}
}
